Java Database Programming with JDBC Java Database Programming with JDBC
by Pratik Patel
Coriolis, The Coriolis Group
ISBN: 1576100561   Pub Date: 10/01/96
  

Previous Table of Contents Next


As you can see, there isn’t a lot going on here for the SimpleText driver; remember that we need to keep the size of the Driver class implementation as small as possible. To aid in this, all of the code required to perform the database connection resides in the Connection class, which we’ll discuss next.

Connection

The Connection class represents a session with the data source. From here, you can create Statement objects to execute SQL statements and gather database statistics. Depending upon the database that you are using, multiple connections may be allowed for each driver.

For the SimpleText driver, we don’t need to do anything more than actually connect to the database. In fact, there really isn’t a database at all—just a bunch of text files. For typical database drivers, some type of connection context will be established, and default information will be set and gathered. During the SimpleText connection initialization, all that we need to do is check for a read-only condition (which can only occur within untrusted applets) and any properties that are supplied by the application, as shown in Listing 10.18.

Listing 10.18 SimpleText connection initialization.

public   void   initialize(
       Driver driver,
         java.util.Properties info)
      throws SQLException
{
    // Save the owning driver object
     ownerDriver = driver;

    // Get the security manager and see if we can write to a file.
    // If no security manager is present, assume that we are a trusted
     // application and have read/write privileges.
    canWrite = false;

    SecurityManager securityManager = System.getSecurityManager ();

    if (securityManager != null) {
        try {
            // Use some arbitrary file to check for file write privileges
            securityManager.checkWrite ("SimpleText_Foo");
            // Flag is set if no exception is thrown
            canWrite = true;
        }
 
       // If we can't write, an exception is thrown. We'll catch
        // it and do nothing.
        catch (SecurityException ex) {
        }
    }
    else {
        canWrite = true;
    }

    // Set our initial read-only flag
    setReadOnly(!canWrite);

    // Get the directory. It will either be supplied in the property
    // list, or we'll use our current default.
    String s = info.getProperty("Directory");

    if (s == null) {
        s = System.getProperty("user.dir");
    }

    setCatalog(s);

}

Creating Statements

From the Connection object, an application can create three types of Statement objects. The base Statement object is used for executing SQL statements directly. The PreparedStatement object (which extends Statement) is used for pre-compiling SQL statements that may contain input parameters. The CallableStatement object (which extends PreparedStatement) is used to execute stored procedures that may contain both input and output parameters.

For the SimpleText driver, the createStatement method does nothing more than create a new Statement object. For most database systems, some type of statement context, or handle, will be created. One thing to note whenever an object is created in a JDBC driver: Save a reference to the owning object because you will need to obtain information (such as the connection context from within a Statement object) from the owning object.

Consider the createStatement method within the Connection class:

public Statement createStatement()
    throws SQLException
{
    if (traceOn()) {
        trace("Creating new SimpleTextStatement");

    }

    // Create a new Statement object
    SimpleTextStatement stmt = new SimpleTextStatement();

     // Initialize the statement
    stmt.initialize(this);
 
   return stmt;

}

Now consider the corresponding initialize method in the Statement class:

public void initialize(
    SimpleTextConnection con)
    throws SQLException
{
    // Save the owning connection object
    ownerConnection = con;
}

Which module will you compile first? You can’t compile the Connection class until the Statement class has been compiled, and you can’t compile the Statement class until the Connection class has been compiled. This is a circular dependency. Of course, the Java compiler does allow multiple files to be compiled at once, but some build environments do not support circular dependency. I have solved this problem in the SimpleText driver by defining some simple interface classes. In this way, the Statement class knows only about the general interface of the Connection class; the implementation of the interface does not need to be present. Our modified initialize method looks like this:

public void initialize(
    SimpleTextIConnection con)
    throws SQLException
{
    // Save the owning connection object
    ownerConnection = con;
}

Note that the only difference is the introduction of a new class, SimpleTextIConnection, which replaces SimpleTextConnection. I have chosen to preface the JDBC class name with an “I” to signify an interface. Here’s the interface class:

public interface SimpleTextIConnection
    extends java.sql.Connection
{
    String[] parseSQL(String sql);
    Hashtable getTables(String directory, String table);
    Hashtable getColumns(String directory, String table);
    String getDirectory(String directory);
}

Note that our interface class extends the JDBC class, and our Connection class implements this new interface. This allows us to compile the interface first, then the Statement, followed by the Connection. Say good-bye to your circular dependency woes.

Now, back to the Statement objects. The prepareStatement and prepareCall methods of the Connection object both require an SQL statement to be provided. This SQL statement should be pre-compiled and stored with the Statement object. If any errors are present in the SQL statement, an exception should be raised, and the Statement object should not be created.

Tell Me About Yourself

One of the most powerful aspects of the JDBC specification (which was inherited from X/Open) is the ability for introspection. This is the process of asking a driver for information about what is supported, how it behaves, and what type of information exists in the database. The getMetaData method creates a DatabaseMetaData object which provides us with this wealth of information.


Previous Table of Contents Next